﻿using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace OpenXmlTools.OpenXML.Word
{
    /// <summary>
    /// Word文本帮助类
    /// </summary>
    public static class WordTextHelper
    {
        /// <summary>
        /// 替换Word文档中的文本内容
        /// </summary>
        /// <param name="fileStream">Word文档流</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param>
        /// <param name="options">替换选项</param>
        /// <returns>Word文档的副本内存流</returns>
        public static MemoryStream ReplaceText(Stream fileStream, Dictionary<string, string> replacements, ReplaceTextOptions? options = null)
        {
            options ??= new ReplaceTextOptions();

            // 创建文档的可写副本
            using var memoryStream = new MemoryStream();
            fileStream.CopyTo(memoryStream);
            memoryStream.Position = 0;
            fileStream.Position = 0;

            // 打开Word文档
            using (WordprocessingDocument doc = WordprocessingDocument.Open(memoryStream, true))
            {
                if (doc.MainDocumentPart != null)
                {
                    // 处理主文档部分
                    ProcessDocumentPart(doc.MainDocumentPart, replacements, options);

                    // 处理页眉
                    foreach (var headerPart in doc.MainDocumentPart.HeaderParts)
                    {
                        ProcessDocumentPart(headerPart, replacements, options);
                    }

                    // 处理页脚
                    foreach (var footerPart in doc.MainDocumentPart.FooterParts)
                    {
                        ProcessDocumentPart(footerPart, replacements, options);
                    }

                    // 处理文本框内容
                    if (options.IncludeTextboxes)
                    {
                        ProcessTextboxes(doc.MainDocumentPart, replacements, options);
                    }

                    // 保存文档
                    doc.MainDocumentPart.Document.Save();
                }
            }

            // 重置流的读取/写入位置到起始点
            memoryStream.Position = 0;

            return memoryStream;
        }

        /// <summary>
        /// 替换Word文档中的文本内容
        /// </summary>
        /// <param name="mainPart">主文档部分</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param>
        /// <param name="options">替换选项</param>
        public static void ReplaceText(MainDocumentPart mainPart, Dictionary<string, string> replacements, ReplaceTextOptions options)
        {
            // 处理主文档部分
            ProcessDocumentPart(mainPart, replacements, options);

            // 处理页眉
            foreach (var headerPart in mainPart.HeaderParts)
            {
                ProcessDocumentPart(headerPart, replacements, options);
            }

            // 处理页脚
            foreach (var footerPart in mainPart.FooterParts)
            {
                ProcessDocumentPart(footerPart, replacements, options);
            }

            // 处理文本框内容
            if (options.IncludeTextboxes)
            {
                ProcessTextboxes(mainPart, replacements, options);
            }
        }

        /// <summary>
        /// 处理文档指定区域
        /// </summary>
        /// <param name="part">文档指定区域</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param>
        /// <param name="options">替换选项</param>
        public static void ProcessDocumentPart(OpenXmlPart? part, Dictionary<string, string> replacements, ReplaceTextOptions options)
        {
            if (part == null)
            {
                return;
            }

            var body = part.RootElement?.Descendants<Body>().FirstOrDefault();
            if (body != null)
            {
                ProcessElement(body, replacements, options);
            }
        }

        /// <summary>
        /// 递归处理文档元素
        /// </summary>
        /// <param name="element">文档元素</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param>
        /// <param name="options">替换选项</param>
        public static void ProcessElement(OpenXmlElement element, Dictionary<string, string> replacements, ReplaceTextOptions options)
        {
            // 处理文本元素
            if (element is Text textElement)
            {
                ReplaceTextInElement(textElement, replacements, options);
                return;
            }

            // 处理段落中的文本
            if (element is Paragraph paragraph)
            {
                foreach (var item in replacements)
                {
                    ReplaceTextInParagraph(paragraph, item.Key, item.Value, options);
                }
                return;
            }

            // 处理表格中的文本
            if (element is Table table)
            {
                foreach (var row in table.Elements<TableRow>())
                {
                    foreach (var cell in row.Elements<TableCell>())
                    {
                        ProcessElement(cell, replacements, options);
                    }
                }
                return;
            }

            // 递归处理子元素
            foreach (var child in element.ChildElements.ToList())
            {
                ProcessElement(child, replacements, options);
            }
        }

        /// <summary>
        /// 在文本元素中执行替换
        /// </summary>
        /// <param name="textElement">原始文本元素</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param>
        /// <param name="options">替换选项</param>
        public static void ReplaceTextInElement(Text textElement, Dictionary<string, string> replacements, ReplaceTextOptions options)
        {
            string originalText = textElement.Text;
            if (string.IsNullOrEmpty(originalText))
            {
                return;
            }

            string newText = originalText;

            // 执行替换
            foreach (var kvp in replacements)
            {
                string oldValue = kvp.Key;
                string newValue = kvp.Value;

                if (options.CaseSensitive)
                {
                    newText = newText.Replace(oldValue, newValue);
                }
                else
                {
                    newText = Regex.Replace(newText, Regex.Escape(oldValue), newValue, RegexOptions.IgnoreCase);
                }
            }

            // 如果文本有变化，更新元素
            if (newText != originalText)
            {
                textElement.Text = newText;
                // 保留空格格式
                PreserveWhitespace(textElement);
            }
        }

        /// <summary>
        /// 替换段落中的指定内容
        /// </summary>
        /// <param name="paragraph">目标段落</param>
        /// <param name="oldText">要替换的文本</param>
        /// <param name="newText">替换后的文本</param>
        /// <param name="options">替换选项</param>
        public static void ReplaceTextInParagraph(Paragraph paragraph, string oldText, string newText, ReplaceTextOptions? options = null)
        {
            options ??= new ReplaceTextOptions();

            // 1. 收集段落中的所有文本元素
            var textElements = paragraph.Descendants<Text>().ToList();
            if (textElements.Count == 0)
            {
                return;
            }

            // 2. 构建段落完整文本
            string fullText = string.Join("", textElements.Select(t => t.Text));

            // 3. 查找所有匹配位置
            var matches = FindTextMatches(fullText, oldText, options);
            if (matches.Count == 0)
            {
                return;
            }

            // 4. 反向处理匹配项（避免索引变化）
            for (int i = matches.Count - 1; i >= 0; i--)
            {
                var match = matches[i];
                ReplaceTextInRange(textElements, match.Start, match.Length, newText);
            }

            // 5. 清理空文本元素
            CleanupEmptyTextElements(paragraph);
        }

        /// <summary>
        /// 查找文本匹配位置
        /// </summary>
        /// <param name="fullText">完整文本</param>
        /// <param name="searchText">查找的文本</param>
        /// <param name="options">替换选项</param>
        /// <returns>文本匹配信息</returns>
        private static List<TextMatch> FindTextMatches(string fullText, string searchText, ReplaceTextOptions options)
        {
            var matches = new List<TextMatch>();
            int currentIndex = 0;

            while (currentIndex < fullText.Length)
            {
                int matchIndex;

                if (options.CaseSensitive)
                {
                    matchIndex = fullText.IndexOf(searchText, currentIndex);
                }
                else
                {
                    matchIndex = fullText.IndexOf(searchText, currentIndex, StringComparison.OrdinalIgnoreCase);
                }

                if (matchIndex == -1)
                {
                    break;
                }

                matches.Add(new TextMatch
                {
                    Start = matchIndex,
                    Length = searchText.Length
                });

                currentIndex = matchIndex + searchText.Length;
            }

            return matches;
        }

        /// <summary>
        /// 替换指定范围的文本
        /// </summary>
        /// <param name="textElements">文本节点</param>
        /// <param name="startIndex">起始位置</param>
        /// <param name="length">长度</param>
        /// <param name="newText">替换文本</param>
        private static void ReplaceTextInRange(List<Text> textElements, int startIndex, int length, string newText)
        {
            int currentIndex = 0;
            int endIndex = startIndex + length;
            List<Text> affectedElements = new List<Text>();

            // 1. 识别受影响的文本元素
            foreach (var textElement in textElements)
            {
                int elementStart = currentIndex;
                int elementEnd = currentIndex + textElement.Text.Length;

                if (elementEnd > startIndex && elementStart < endIndex)
                {
                    affectedElements.Add(textElement);
                }

                currentIndex = elementEnd;
                if (currentIndex >= endIndex)
                {
                    break;
                }
            }

            if (affectedElements.Count == 0)
            {
                return;
            }

            // 2. 处理单个文本元素的情况
            if (affectedElements.Count == 1)
            {
                ReplaceInSingleTextElement(affectedElements[0], startIndex, length, newText);
                return;
            }

            // 3. 处理跨多个文本元素的情况
            ReplaceAcrossMultipleTextElements(affectedElements, startIndex, endIndex, newText);
        }

        /// <summary>
        /// 在单个文本元素中替换文本
        /// </summary>
        /// <param name="textElement">文本节点</param>
        /// <param name="startIndex">起始位置</param>
        /// <param name="length">长度</param>
        /// <param name="newText">替换文本</param>
        private static void ReplaceInSingleTextElement(Text textElement, int startIndex, int length, string newText)
        {
            string text = textElement.Text;
            int localStart = startIndex - (GetGlobalIndex(textElement) ?? 0);
            string newContent = text[..localStart] + newText + text[(localStart + length)..];

            textElement.Text = newContent;
            PreserveWhitespace(textElement);
        }

        /// <summary>
        /// 跨多个文本元素替换文本
        /// </summary>
        /// <param name="affectedElements"></param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        /// <param name="newText"></param>
        private static void ReplaceAcrossMultipleTextElements(List<Text> affectedElements, int startIndex, int endIndex, string newText)
        {
            // 获取第一个元素
            var firstElement = affectedElements.First();
            int firstElementStart = GetGlobalIndex(firstElement) ?? 0;

            // 获取最后一个元素
            var lastElement = affectedElements.Last();
            int lastElementStart = GetGlobalIndex(lastElement) ?? 0;

            // 处理第一个元素
            int firstLocalStart = startIndex - firstElementStart;
            string firstText = firstElement.Text;
            string firstNewContent = firstText.Substring(0, firstLocalStart);
            firstElement.Text = firstNewContent;

            // 处理中间元素（清空内容）
            for (int i = 1; i < affectedElements.Count - 1; i++)
            {
                affectedElements[i].Text = string.Empty;
            }

            // 处理最后一个元素
            int lastLocalEnd = endIndex - lastElementStart;
            string lastText = lastElement.Text;
            string lastNewContent = lastText.Substring(lastLocalEnd);
            lastElement.Text = lastNewContent;

            //// 在第一个元素后插入新内容
            //Run newRun = CreateFormattedRun(newText, firstElement.Parent as Run);
            //firstElement?.Parent?.InsertAfter(newRun, firstElement.Parent);

            // 在第一个元素的父元素后插入新内容
            var firstElementParent = firstElement.Parent;
            if (firstElementParent == null) return;

            // 创建带格式的新Run
            Run newRun = CreateFormattedRun(newText, firstElementParent as Run);

            // 安全插入
            SafeInsertAfter(newRun, firstElementParent);

        }

        /// <summary>
        /// 获取文本元素的全局索引
        /// </summary>
        /// <param name="textElement">文本元素</param>
        /// <returns></returns>
        private static int? GetGlobalIndex(Text textElement)
        {
            // 获取父段落
            if (!(textElement.Ancestors<Paragraph>().FirstOrDefault() is Paragraph paragraph))
                return null;

            // 计算全局索引
            int index = 0;
            foreach (var text in paragraph.Descendants<Text>())
            {
                if (text == textElement) return index;
                index += text.Text.Length;
            }

            return null;
        }

        /// <summary>
        /// 安全插入元素
        /// </summary>
        /// <param name="newElement">待插入的元素</param>
        /// <param name="referenceElement">插入位置关联的元素</param>
        private static void SafeInsertAfter(OpenXmlElement newElement, OpenXmlElement referenceElement)
        {
            if (referenceElement == null || newElement == null)
            {
                return;
            }

            OpenXmlElement? parent = referenceElement.Parent;
            if (parent == null)
            {
                return;
            }

            // 检查参考元素是否是父元素的直接子节点
            if (parent.ChildElements.Contains(referenceElement))
            {
                parent.InsertAfter(newElement, referenceElement);
            }
            else
            {
                // 尝试查找位置
                int index = FindElementIndex(parent, referenceElement);
                if (index >= 0)
                {
                    parent.InsertAt(newElement, index + 1);
                }
                else
                {
                    // 添加到末尾
                    parent.AppendChild(newElement);
                }
            }
        }

        /// <summary>
        /// 查找元素在父元素中的位置
        /// </summary>
        /// <param name="parent">父元素</param>
        /// <param name="element">查找的元素</param>
        /// <returns>元素在父元素中的位置索引</returns>
        private static int FindElementIndex(OpenXmlElement parent, OpenXmlElement element)
        {
            for (int i = 0; i < parent.ChildElements.Count; i++)
            {
                if (parent.ChildElements[i] == element)
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// 处理文本框中的文本
        /// </summary>
        /// <param name="mainDocumentPart">文档主体部分</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param>
        /// <param name="options">替换选项</param>
        public static void ProcessTextboxes(MainDocumentPart mainDocumentPart, Dictionary<string, string> replacements, ReplaceTextOptions options)
        {
            // 获取所有文本框元素
            var textboxes = mainDocumentPart.Document.Descendants<DocumentFormat.OpenXml.Vml.TextBox>().ToList();

            foreach (var textbox in textboxes)
            {
                // 获取文本框内的所有文本元素
                var textElements = textbox.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>().ToList();

                // 如果没有文本元素，尝试获取段落内的文本
                if (textElements.Count == 0)
                {
                    var paragraphs = textbox.Descendants<DocumentFormat.OpenXml.Wordprocessing.Paragraph>();
                    foreach (var para in paragraphs)
                    {
                        textElements.AddRange(para.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>());
                    }
                }

                // 处理所有文本元素
                foreach (var textElement in textElements)
                {
                    string originalText = textElement.Text;
                    if (string.IsNullOrEmpty(originalText))
                    {
                        continue;
                    }

                    string newText = originalText;

                    foreach (var kvp in replacements)
                    {
                        string oldValue = kvp.Key;
                        string newValue = kvp.Value;

                        if (options.CaseSensitive)
                        {
                            newText = newText.Replace(oldValue, newValue);
                        }
                        else
                        {
                            newText = Regex.Replace(newText, Regex.Escape(oldValue), newValue, RegexOptions.IgnoreCase);
                        }
                    }

                    if (newText != originalText)
                    {
                        textElement.Text = newText;
                        // 保留空格格式
                        PreserveWhitespace(textElement);
                    }
                }
            }
        }

        /// <summary>
        /// 高级文本替换（支持正则表达式）
        /// </summary>
        /// <param name="fileStream">Word文档流</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param>
        /// <param name="options">替换选项</param>
        /// <returns>Word文档的副本内存流</returns>
        public static MemoryStream AdvancedReplaceText(Stream fileStream, Dictionary<string, string> replacements, ReplaceTextOptions? options = null)
        {
            options ??= new ReplaceTextOptions();

            using var memoryStream = new MemoryStream();
            fileStream.CopyTo(memoryStream);
            memoryStream.Position = 0;
            fileStream.Position = 0;

            using (WordprocessingDocument doc = WordprocessingDocument.Open(memoryStream, true))
            {
                if (doc.MainDocumentPart != null)
                {
                    var body = doc.MainDocumentPart.Document.Body;
                    ProcessElementWithRegex(body, replacements, options);
                    doc.MainDocumentPart.Document.Save();
                }
            }

            // 重置流的读取/写入位置到起始点
            memoryStream.Position = 0;

            return memoryStream;
        }

        /// <summary>
        /// 使用正则表达式处理元素
        /// </summary>
        /// <param name="element">文档元素</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param>
        /// <param name="options">替换选项</param>
        public static void ProcessElementWithRegex(OpenXmlElement element, Dictionary<string, string> replacements, ReplaceTextOptions options)
        {
            if (element is Text textElement)
            {
                string originalText = textElement.Text;
                if (string.IsNullOrEmpty(originalText))
                {
                    return;
                }

                string newText = originalText;

                foreach (var kvp in replacements)
                {
                    string pattern = kvp.Key;
                    string replacement = kvp.Value;

                    RegexOptions regexOptions = options.CaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase;
                    newText = Regex.Replace(newText, pattern, replacement, regexOptions);
                }

                if (newText != originalText)
                {
                    textElement.Text = newText;
                }
                return;
            }

            // 处理表格
            if (element is Table table)
            {
                foreach (var row in table.Elements<TableRow>())
                {
                    foreach (var cell in row.Elements<TableCell>())
                    {
                        ProcessElementWithRegex(cell, replacements, options);
                    }
                }
                return;
            }

            // 递归处理子元素
            foreach (var child in element.ChildElements.ToList())
            {
                ProcessElementWithRegex(child, replacements, options);
            }
        }

        /// <summary>
        /// 替换文本并保留格式（处理跨Run的文本）
        /// </summary>
        /// <param name="fileStream">Word文档流</param>
        /// <param name="replacements">替换字典（旧文本 -> 新文本）</param> 
        /// <returns>Word文档的副本内存流</returns>
        public static MemoryStream ReplaceTextWithFormatting(Stream fileStream, Dictionary<string, string> replacements)
        {
            using var memoryStream = new MemoryStream();
            fileStream.CopyTo(memoryStream);
            memoryStream.Position = 0;
            fileStream.Position = 0;

            using (WordprocessingDocument doc = WordprocessingDocument.Open(memoryStream, true))
            {
                if (doc.MainDocumentPart != null)
                {
                    var body = doc.MainDocumentPart.Document.Body;
                    if (body != null)
                    {
                        foreach (var kvp in replacements)
                        {
                            ReplaceTextAcrossRuns(body, kvp.Key, kvp.Value);
                        }
                        doc.MainDocumentPart.Document.Save();
                    }
                }
            }

            // 重置流的读取/写入位置到起始点
            memoryStream.Position = 0;

            return memoryStream;
        }

        /// <summary>
        /// 处理跨多个Run的文本替换
        /// </summary>
        /// <param name="parent">父级元素</param>
        /// <param name="oldText">原始文本</param>
        /// <param name="newText">替换文本</param>
        public static void ReplaceTextAcrossRuns(OpenXmlElement parent, string oldText, string newText)
        {
            // 收集所有文本节点
            var textNodes = parent.Descendants<Text>().ToList();
            if (textNodes.Count == 0)
            {
                return;
            }

            // 构建完整文本
            string fullText = string.Concat(textNodes.Select(t => t.Text));

            // 查找所有匹配位置
            var matches = new List<TextMatch>();
            int index = 0;
            while (index < fullText.Length)
            {
                int matchIndex = fullText.IndexOf(oldText, index, StringComparison.OrdinalIgnoreCase);
                if (matchIndex == -1)
                {
                    break;
                }

                matches.Add(new TextMatch
                {
                    Start = matchIndex,
                    End = matchIndex + oldText.Length
                });

                index = matchIndex + oldText.Length;
            }

            if (matches.Count == 0)
            {
                return;
            }

            // 反向处理匹配项（避免索引变化）
            for (int i = matches.Count - 1; i >= 0; i--)
            {
                var match = matches[i];
                ReplaceTextInRange(textNodes, match.Start, match.End - match.Start, newText);
            }
        }

        /// <summary>
        /// 创建带格式的文本区域
        /// </summary>
        /// <param name="text">文本</param>
        /// <param name="referenceRun">格式文本区域</param>
        /// <returns>带格式的文本区域</returns>
        public static Run CreateFormattedRun(string text, Run? referenceRun = null)
        {
            var newRun = new Run();

            // 复制参考Run的格式
            if (referenceRun != null && referenceRun.RunProperties != null)
            {
                newRun.RunProperties = (RunProperties)referenceRun.RunProperties.CloneNode(true);
            }

            newRun.AppendChild(new Text(text));
            return newRun;
        }

        /// <summary>
        /// 保留文本中的空格
        /// </summary>
        /// <param name="textElement">文本元素</param>
        private static void PreserveWhitespace(Text textElement)
        {
            if (textElement.Parent is Run run && run.RunProperties != null)
            {
                run.RunProperties.SetAttribute(
                    new OpenXmlAttribute(
                        "space",
                        "http://www.w3.org/XML/1998/namespace",
                        "preserve"));
            }
        }

        /// <summary>
        /// 清理空文本元素
        /// </summary>
        /// <param name="paragraph">目标段落</param>
        public static void CleanupEmptyTextElements(Paragraph paragraph)
        {
            var emptyTexts = paragraph.Descendants<Text>().Where(t => string.IsNullOrEmpty(t.Text)).ToList();

            foreach (var text in emptyTexts)
            {
                // 如果Text元素是Run的唯一内容，则删除整个Run
                if (text.Parent is Run run && run.ChildElements.Count == 1)
                {
                    run.Remove();
                }
                // 否则只删除Text元素
                else
                {
                    text.Remove();
                }
            }
        }

    }
}
